/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2004 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache Lucene" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache Lucene", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * $Id: SimpleQueryTokenManager.java,v 1.2 2004/10/30 09:58:25 lhelper Exp $
 */
package org.apache.lucene.queryParser;

import java.io.IOException;
import java.io.StringReader;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;

/**
 * Converts a Lucene token stream to a JavaCC TokenManager. Text between Lucene
 * tokens is also examined for special characters which are returned as JavaCC
 * tokens so that they can be used in query parsing.
 */

public class SimpleQueryTokenManager implements TokenManager, SimpleQueryParserConstants {
	private TokenStream source;
	private String text;

	private org.apache.lucene.analysis.Token token; // the Lucene token
	private int offset = 0;

	public SimpleQueryTokenManager(String t, Analyzer analyzer) {
		source = analyzer.tokenStream("", new StringReader(t));
		text = t;
	}

	public Token getNextToken() { // translate from source
		try {
			if (token == null || offset > token.startOffset())
				token = source.next();

			// Examine text between tokens for special characters.
			int end = (token == null) ? text.length() : token.startOffset();
			for (; offset < end; offset++) {
				Token t = null;

				switch (text.charAt(offset)) { // return special char tokens
				case '+':
					t = newToken(PLUS, offset, offset + 1, "+");
					break;
				case '-':
					t = newToken(MINUS, offset, offset + 1, "-");
					break;
				case ':':
					t = newToken(COLON, offset, offset + 1, ":");
					break;
				case '(':
					t = newToken(OPEN, offset, offset + 1, "(");
					break;
				case ')':
					t = newToken(CLOSE, offset, offset + 1, ")");
					break;
				case '"':
					t = newToken(QUOTE, offset, offset + 1, "\"");
					break;
				}

				// Check for special tokens
				if (tokenTextIs("AND", offset, end))
					t = newToken(AND, offset, offset + 3, "AND");
				else if (tokenTextIs("OR", offset, end))
					t = newToken(OR, offset, offset + 2, "OR");
				else if (tokenTextIs("NOT", offset, end))
					t = newToken(NOT, offset, offset + 3, "NOT");

				if (t != null) {
					offset = t.endColumn;
					return t;
				}
			}

			if (token == null) // at end of input
				return newToken(EOF, offset, offset, "");

			offset = token.endOffset();

			// Not a special token: convert Lucene token
			return newToken(TERM, token.startOffset(), token.endOffset(), token.termText());

		} catch (IOException e) {
			throw new RuntimeException(e.toString());
		}
	}

	private final Token newToken(int ofKind, int begin, int end, String i) {
		Token token = new Token();
		token.kind = ofKind;
		token.beginColumn = begin;
		token.endColumn = end;
		token.image = i;
		return token;
	}

	private boolean tokenTextIs(String s, int offset, int end) {
		// Return true iff the input text at offset matches s.
		if (offset + s.length() >= end)
			return false;
		for (int i = 0; i < s.length(); i++)
			if (s.charAt(i) != text.charAt(offset + i))
				return false;
		return true;
	}
}
